#include "FilterLinear.h"
#include <cmath>



FilterLinear::FilterLinear (const Core< float > & core)
{
	setFilterCore (core);
}



FilterLinear::FilterLinear (const FilterLinear & right)
: _filterCore (right._filterCore), _scale (right._scale)
{

}



FilterLinear::~FilterLinear ()
{

}



const Core< float > & FilterLinear::getFilterCore () const
{
	return _filterCore;
}

Core< float > & FilterLinear::getFilterCore ()
{
	return _filterCore;
}

Ptr< QImage > FilterLinear::process (Ptr< QImage > pSrcImg)
{
	Ptr< QImage > pDesImg = new QImage (pSrcImg->size (), QImage::Format_ARGB32);
	int coreHeight = _filterCore.getSize ().height ();
	int coreWidth = _filterCore.getSize ().width ();
	int coreCenterX = _filterCore.getCenter ().x ();
	int coreCenterY = _filterCore.getCenter ().y ();

	int width = pSrcImg->width ();
	int height = pSrcImg->height ();
	int bytesPerPixel = 4;
	int bytesPerLine = pSrcImg->bytesPerLine ();
	float * newVal = new float[bytesPerPixel];

	for (int v = 0; v < height; ++v) {
		const uchar * srcLine = pSrcImg->scanLine (v);
		uchar * desLine = pDesImg->scanLine (v);
		for (int u = 0; u < bytesPerLine; u += bytesPerPixel) {
			memset (newVal, 0, sizeof (float) * bytesPerPixel);
			for (int cv = 0; cv < coreHeight; ++cv) {
				int srcCalcLineNum = v + cv - coreCenterY;

				// handle for top and bottom border
				if (srcCalcLineNum < 0)
					srcCalcLineNum = 0;
				else if (srcCalcLineNum > height - 1)
					srcCalcLineNum = height - 1;

				const uchar * srcCalcLine = pSrcImg->scanLine (srcCalcLineNum);

				for (int cu = 0; cu < coreWidth; ++cu) {
					int p = u + (cu - coreCenterX) * bytesPerPixel;

					// handle for left and right border
					if (p < 0)
						p = 0;
					else if (p > bytesPerLine - 1)
						p = bytesPerLine - 1;

					// For each color part apply convolve
					for (int i = 0; i < bytesPerPixel; ++i)
						newVal[i] += _filterCore(cu, cv) * srcCalcLine[p + i];
				}
			}
			for (int i = 0; i < bytesPerPixel - 1; ++i)
				desLine[u + i] = (newVal[i] - _coreMin * 255) * _scale;
			desLine[u + 3] = srcLine[u + 3];
		}
	}
	delete [] newVal;
	return pDesImg;

}

void FilterLinear::setFilterCore (const Core< float > & core)
{
	_filterCore = core;
	_coreMax = 0.0f;
	_coreMin = 0.0f;
	int coreHeight = _filterCore.getSize ().height ();
	int coreWidth = _filterCore.getSize ().width ();
	for (int v = 0; v < coreHeight; ++v)
	{
		for (int u = 0; u < coreWidth; ++u)
			if (_filterCore(u, v) < 0)
				_coreMin += _filterCore(u, v);
			else
				_coreMax += _filterCore(u, v);
	}
	_scale = 1.0 / (_coreMax - _coreMin);
}
